<?php
/*
 * @Author: your name
 * @Date: 2020-10-15 10:07:53
 * @LastEditTime: 2021-01-04 14:23:43
 * @LastEditors: Please set LastEditors
 * @Description: 端口伪装方法封装
 * @FilePath: /special/application/adminapiv3/service/module_manage/disguise/PortMaskService.php
 */
namespace app\adminapiv3\service\module_manage\disguise;

use app\adminapiv3\service\BaseService;
use app\common\exception\CustomException;
use app\common\service\HostLink;
use app\common\definition\disguise\DisguiseStatusDefinition;
use app\common\definition\InternetProtocolsDefinition;
use think\Db;

class DisguiseService extends BaseService
{
    /**
     * @name: 开启端口伪装
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-10-31 16:37:25
     */
    public function on ($data)
    {
        $HostLink = new HostLink();
        $HostLink->checkOnline('disguise');
        
        $host_id_a = $this->getHost('id');
        //检查上传伪装端口
        $port_a = $this->checkDisguisePort($data);
        //添加伪装端口数据
        $insertData = $this->addDisguisePort($host_id_a, $port_a);

        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $port_a = array_map(function($v){
            return '[' . $v['protocols'] . ']' . $v['port'];
        },$insertData);
        $logArray = array(
            'content' => '开启端口伪装',
            'new_info' => '涉及主机:' . $host_name_s . '开启端口' . implode(',', $port_a)
        );

        Db::startTrans();
        try {
            //删除所有伪装端口号
            Db::name('HostGuisePort')->whereIn('host_id', $host_id_a)->delete();
            //添加端端口号
            Db::name('HostGuisePort')->insertAll($insertData);
            //修改伪装状态为开启伪装状态
            Db::name('HostGuiseConfig')->whereIn('host_id', $host_id_a)->update(['guise_status' => DisguiseStatusDefinition::ENABLE]);
            
            Db::commit();
        } catch (\think\Exception $e)
        {
            Db::rollback();
            throw new CustomException('开启系统伪装失败:'.$e->getMessage(), 302);
        }
    }

    /**
     * @name: 关闭端口伪装
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-10-31 16:37:39
     */
    public function off ()
    {
        $HostLink = new HostLink();
        $HostLink->checkOnline('disguise');
        
        $host_id_a = $this->getHost('id');

        Db::name('HostGuiseConfig')->whereIn('host_id', $host_id_a)->update(['guise_status' => DisguiseStatusDefinition::DISABLE]);

        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $logArray = array(
            'content' => '关闭端口伪装',
            'new_info' => '涉及主机:' . $host_name_s
        );
    }

    /**
     * @name: 伪装端口修改
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-01 10:30:53
     */
    public function configModify ($data)
    {
        $host_id_a = $this->getHost('id');

        //检查上传伪装端口
        $port_a = $this->checkDisguisePort($data);
        //添加伪装端口数据
        $insertData = $this->addDisguisePort($host_id_a, $port_a);

        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $port_a = array_map(function($v){
            return '[' . $v['protocols'] . ']' . $v['port'];
        },$insertData);
        $logArray = array(
            'content' => '修改端口伪装配置',
            'new_info' => '涉及主机:' . $host_name_s . '开启端口' . implode(',', $port_a)
        );

        Db::startTrans();
        try {
            //删除所有伪装端口号
            Db::name('HostGuisePort')->whereIn('host_id', $host_id_a)->delete();
            //添加端端口号
            Db::name('HostGuisePort')->insertAll($insertData);

            Db::commit();
        } catch (\think\Exception $e)
        {
            Db::rollback();
            throw new CustomException('修改伪装端口失败:'.$e->getMessage(), 302);
        }
        
    }

    /**
     * @name: 端口伪装详情
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-01 10:45:18
     */
    public function configInfo ($host_id)
    {
        $data = Db::name('HostGuisePort')->field('type,GROUP_CONCAT(port) as port')->where('host_id', $host_id)->group('type')->select();
        $data = array_column($data, 'port', 'type');

        $return = [
            'middleware' => 0,
            'sql' => 0,
            'standard' => 0,
            'tcp' => '',
            'udp' => '',
        ];

        $return = array_merge($return, $data);

        return $return;
    }

    /**
     * @name: 端口伪装列表
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-01 11:23:17
     */
    public function list ($filterData)
    {
        $status = Db::name('HostGuiseConfig')->where('host_id', $filterData['host_id'])->value('guise_status');

        if (!$status)
        {
            return [];
        }

        $server = Db::name('HostGuisePort')->field('id,port,protocols,status,type')->where('host_id', $filterData['host_id']);

        isset($filterData['port']) && is_numeric($filterData['port']) ? $server->whereLike('port', '%' . $filterData['port'] . '%') : '';
        isset($filterData['protocols']) && is_numeric($filterData['protocols']) ? $server->where('protocols', $filterData['protocols']) : '';
        isset($filterData['status']) && is_numeric($filterData['status']) ? $server->where('status', $filterData['status']) : '';
        
        $return = $server->paginate()->toArray();

        return $return;
    }

    /**
     * @name: 添加伪装端口
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-12-07 16:18:05
     */
    private function addDisguisePort ($host_id_a, $port_a)
    {
        $return = [];
        foreach ($host_id_a as $host_id)
        {
            if ($port = Db::name('HostPort')->whereIn('port', $port_a)->where('host_id', $host_id)->where('guise', DisguiseStatusDefinition::DISABLE)->column('port'))
            {
                throw new CustomException($this->hostErrorMessage([$host_id], '已存在' . implode(',', $port) . '端口'), 422);
            }
            
            foreach ($port_a as $k => $v)
            {
                $va = explode(',', $v);
                foreach ($va as $cv)
                {
                    if(!empty($cv))
                    {
                        $return[] = [
                            'host_id' => $host_id,
                            'port' => $cv,
                            'protocols' => $k == 'udp' ? InternetProtocolsDefinition::UDP_PROTOCOL : InternetProtocolsDefinition::TCP_PROTOCOL ,
                            'status' => DisguiseStatusDefinition::ENABLE,
                            'type' => $k
                        ];
                    }
                    
                }
            }
        }

        return $return;
    }

    /**
     * @name: 检查伪装端口
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-12-07 16:19:38
     */
    private function checkDisguisePort ($input)
    {
        $port_s = '';
        foreach ($input as $value)
        {
            if(!empty($value))
            {
                $port_s .= $value.',';
            }
        }
        
        $port_s = substr($port_s, '0', strlen($port_s) -1);
        $port_a = explode(',', $port_s);
        $port_a_unique = array_unique($port_a);
        
        if(count($port_a_unique) != count($port_a))
        {
            throw new CustomException('上传数据中存在重复数值', 422);
        }

        return $input;
    }

    /**
     * @name: 获取设置接管了防火墙的主机
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-12-25 15:21:13
     */
    public function getControlledFirewallHost ()
    {
        $host_id_a= $this->getHost('id');
        
        return Db::name('host_learn_config')->whereIn('host_id', $host_id_a)->where('controlled_firewall', 1)->column('host_id');
        
    }
}